package sketch.generator.examples;

import java.util.ArrayList;
import java.util.List;

import sketch.generator.CompositeGenerator;
import sketch.generator.ExhaustiveValueGenerator;
import sketch.generator.IGenerator;
import sketch.generator.IIterationLink;
import sketch.generator.LinkCreator;
import sketch.util.Checker;

public class PermutationSequentialValueGenerator<T> extends CompositeGenerator<SequentialValue<T>> {

	private List<IGenerator<T>> generators = new ArrayList<IGenerator<T>>();
	
	public PermutationSequentialValueGenerator() {
		super();
	}
	
	public PermutationSequentialValueGenerator(IGenerator<T>...generators) {
		this();
		Checker.checkNull(generators, "generators could not be null.");
		for(IGenerator<T> generator : generators) {
			Checker.checkNull(generator, "a single generator could not be null.");
			this.generators.add(generator);
		}
	}
	
	public void add(IGenerator<T> generator) {
		Checker.checkNull(generator, "The newly added generator could not be null!");
		Checker.checkTrue(!(generator instanceof ExhaustiveValueGenerator), "To avoid infinite loop, it could not be an ExhaustiveValueGenerator!");
		Checker.checkTrue(!(generator instanceof ExhaustiveSequatialValueGenerator), "To avoid infinite loop, it could not be an ExhaustiveSequatialValueGenerator!");
		this.generators.add(generator);
		//reset the state
		reset();
	}
	
	@Override
	public void reset() {
		super.reset();
		for(IGenerator<T> generator : generators) {
			generator.reset();
		}
	}
	
	
	@Override
	public SequentialValue<T> generateCurrent() {
		List<T> generatedValues = new ArrayList<T>();
		
		for(IGenerator<T> generator : generators) {
			generatedValues.add(generator.current());
		}
		
		SequentialValue<T> assembledValue = new SequentialValue<T>(generatedValues);
		return assembledValue;
	}

	@Override
	public IIterationLink getInitializedIterator() {
		return LinkCreator.createInOrderGenCombinatoricLink((IGenerator<T>[]) generators.toArray(new IGenerator[0]));
	}

}
